/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javamail.sip;

import java.util.Hashtable;
import javamail.sip.util.eSipCallState;

/**
 *
 * @author sriram
 */
public class sipCallManager {
    private Hashtable<String, sipCall> callPool = null;
    private static final boolean debugEnabled = true;
    private static sipCallManager mgr = null;

    public sipCallManager() {
        callPool = new Hashtable<String, sipCall>(10);
    }
    
    public static sipCallManager getInstance() {
        if(mgr == null) {
            mgr = new sipCallManager();
            if(debugEnabled)
                System.out.println("sipCallManager::getInstance-Creating a new sip Call manager instance");
        }
        return mgr;
    }
    
    // Gets an existing call with the callid specified. 
    // Returns null if there no existing call.
    public sipCall getCall(String callid) {
        if(callid != null)
            synchronized(callPool) {
                return callPool.get(callid);
            }
        if(debugEnabled)
            System.out.println("sipCallManager::getCall-Callid does not exist!");
        return null;
    }

    // Gets an existing call with the same FROM and TO address.
    public sipCall getCallFromAddress(String from) {
        if(from!=null) {
            for(sipCall call: callPool.values()) {
                if(call.matchesFromTo(from))
                    return call;
            }
        }
        if(debugEnabled)
            System.out.println("sipCallManager::getcall()-Unable to find matching call");
        return null;
    }

    public eSipCallState getState(String callid) {
        eSipCallState state = eSipCallState.not_in_call;
        synchronized(callPool) {
            if(callPool.get(callid) != null)
                state = callPool.get(callid).getState();
        }
        return state;
    }
    
    public sipCall getCall(sipMessage msg) {
        sipCall call = getCall(msg.getCallid());
        // If there is no existing call with this callid.
        // Create a new one and insert in the callPool
        if(call == null) {
            if(debugEnabled)
                System.out.println("sipCallManager::getCall-Creating a new call!");
            call = new sipCall(msg.getCallid(), msg.getFromAddress());
            callPool.put(msg.getCallid(), call);
        }
        return call;
    }
    
    public void processInvite(sipMessage msg) {
        if(debugEnabled)
            System.out.println("sipCallManager::processInvite-Received an INVITE from: " + msg.getFromAddress());
        boolean isCallComplete = false;
        sipCall call = getCall(msg);
        synchronized(call) {
            isCallComplete = call.processInvite(msg);
        }
        if(isCallComplete) {
            synchronized(callPool) {
                callPool.remove(msg.getCallid());
                if(debugEnabled)
                    System.out.println("sipCallManager::processInvite-Call object removed:"+msg.getCallid());
            }
        }
    }

    public void process200OK(sipMessage msg) {
        if(debugEnabled)
            System.out.println("sipCallManager::process200OK-Received 200 OK from: " + msg.getFromAddress());
        boolean isCallComplete = false;
        sipCall call = getCall(msg.getCallid());
        if(call==null) {
            if(debugEnabled)
                System.out.println("sipCallManager::process200OK-Invalid CALLID");
            return;
        }
        synchronized(call) {
            isCallComplete = call.process200OK(msg);
        }
        if(isCallComplete) {
            synchronized(callPool) {
                callPool.remove(msg.getCallid());
                if(debugEnabled)
                    System.out.println("sipCallManager::process200OK-Call object removed:"+msg.getCallid());
            }
        }
        if(debugEnabled)
            System.out.println("sipCallManager::process200OK-Finished processing 200 OK");
    }

    public void processAck(sipMessage msg) {
        if(debugEnabled)
            System.out.println("sipCallManager::processAck-Received an ACK from: " + msg.getFromAddress());
        sipCall call = getCall(msg.getCallid());
        if(call==null) {
            if(debugEnabled)
                System.out.println("sipCallManager::processAck-Invalid CALLID");
            return;
        }
        synchronized(call) {
            call.processAck(msg);
        }
        if(debugEnabled)
            System.out.println("sipCallManager::processAck-Finished processing ACK");
    }
    
    public void processBye(sipMessage msg) {
        boolean isCallComplete = false;
        if(debugEnabled)
            System.out.println("sipCallManager::processBye-Received a BYE from: " + msg.getFromAddress());
        sipCall call = getCall(msg.getCallid());
        if(call==null) {
            if(debugEnabled)
                System.out.println("sipCallManager::processBye-Invalid CALLID");
            return;
        }
        synchronized(call) {
            isCallComplete = call.processBye(msg);
        }
        if(isCallComplete) {
            synchronized(callPool) {
                callPool.remove(msg.getCallid());
                if(debugEnabled)
                    System.out.println("sipCallManager::processBye-Call object removed:"+msg.getCallid());
            }
        }
        if(debugEnabled)
            System.out.println("sipCallManager::processBye()-Finished processing BYE");
    }

    public void processMessage(sipMessage msg) {
        if(debugEnabled)
            System.out.println("sipCallManager::processMessage-Received a MESSAGE from: " + msg.getFromAddress());
        // Get the call using only thte VIA address.
        sipCall call = getCallFromAddress(msg.getViaHostOnly());
        if(call==null) {
            if(debugEnabled)
                System.out.println("sipCallManager::processMessage-Invalid CALLID");
            return;
        }
        synchronized(call) {
            call.processMessage(msg);
        }
        if(debugEnabled)
            System.out.println("sipCallManager::processMessage-Finished processing Message");
    }

    // Handlers for events raised by the speech manager
    public void processSpeechEvent(String callid, String message) {
        if(debugEnabled)
            System.out.println("sipCallManager::processSpeechEvent()-Received a MESSAGE from speech manager");
        sipCall call = getCall(callid);
        if(call==null) {
            if(debugEnabled)
                System.out.println("sipCallManager::processSpeechEvent()-Invalid CALLID");
            return;
        }
        synchronized(call) {
            //call.processSpeechEvent(message);
        }
        if(debugEnabled)
            System.out.println("sipCallManager::processSpeechEvent()-Finished processing Speech Event");
    }

    public void processCallTakeDownEvent(String callid) {
        if(debugEnabled)
            System.out.println("sipCallManager::processCallTakeDownEvent()-Received a Call take down from speech manager");
        sipCall call = getCall(callid);
        if(call==null) {
            if(debugEnabled)
                System.out.println("sipCallManager::processCallTakeDownEvent()-Invalid CALLID");
            return;
        }
        synchronized(call) {
            call.sendBye();
        }
        if(debugEnabled)
            System.out.println("sipCallManager::processCallTakeDownEvent()-Finished processing call take down event");
    }

}
